package com.jwww.support.mybatis.query;

import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jwww.support.helper.BeanConverter;
import com.jwww.support.mybatis.MybatisMapperResultConverter;
import com.jwww.support.mybatis.SqlChecker;

/**
 * mybatisCRUD通用查询对象（查询字段为entity字段）
 * @author jwww
 * @date 2015年4月1日下午3:42:33
 * @description <br>
 * Copyright (c) 2015, vakinge@gmail.com.
 */
public class EntityQuery implements Serializable{
	
	protected static final Logger LOG = LoggerFactory.getLogger(EntityQuery.class);

	private static final long serialVersionUID = -8100262635652136584L;
	
	private Map<String, Object> params = new HashMap<String, Object>();
	
	public static final String SORT_REGEX = "([a-zA-Z]{2,32}\\s+(desc|asc),?)+";
	
	private String selectFields = "*";
	private int startIndex = 0;
	private int pageLimit = 10;
	private String sortAs;
	private String where;
	
	private Class<?> entityClass;
	
	
	
	public EntityQuery() {}
	
	/**
	 * 使用此构造方法默认主键属性为：id
	 * @param pk
	 */
	public EntityQuery(Serializable pk) {
		params.put("id", pk);
	}

	/**
	 * 设置主键
	 * @param idProperty
	 * @param pk
	 * @return
	 */
	public EntityQuery setPK(String idProperty,Serializable pk){
		params.put(idProperty, pk);
		return this;
	}
	
	
	/**
	 * 添加查询条件
	 * @param field 对应实体属性
	 * @param value
	 * @return
	 */
	public EntityQuery addParam(String field, Object value){
		if(value != null)params.put(field, value);
		return this;
	}
	
	/**
	 * 清除一个查询条件
	 * @param field
	 * @return
	 */
	public EntityQuery removeParam(String field){
		if(params.containsKey(field))params.remove(field);
		return this;
	}
	
	/**
	 * 把对象指定属性放入参数集合
	 * @param obj  
	 * @param includeAction 是否包含操作（true:则处理fields包含的字段，false：处理fields不包含的字段）
	 * @param fields 包含或排除字段
	 * @return
	 */
	public EntityQuery addParams(Object obj,boolean includeAction, String...fields){
		
		List<String> fieldList = Arrays.asList(fields);
		
		Map<?, ?> map = BeanConverter.beanToMap(obj);
		
		String field;
		for (Object key : map.keySet()) {
			field = key.toString();
			if(map.get(field) == null)continue;
			if(fieldList.contains(field)){
				if(includeAction){
					params.put(field, map.get(field));
				}
			}else{
				if(!includeAction){
					params.put(field, map.get(field));
				}
			}
		}

		return this;
	}
	
	public EntityQuery selectFields(String selectFields) {
		this.selectFields = selectFields;
		return this;
	}

	public EntityQuery startIndex(int startIndex) {
		this.startIndex = startIndex;
		return this;
	}

	public EntityQuery pageLimit(int pageLimit) {
		this.pageLimit = pageLimit;
		return this;
	}

	public EntityQuery sortAs(String sortAs) {
		if(StringUtils.isNotBlank(sortAs)){
			this.sortAs = sortAs;
		}
		return this;
	}

	public String getSelectFields() {
		return selectFields;
	}

	public int getStartIndex() {
		return startIndex;
	}

	public int getPageLimit() {
		return pageLimit;
	}

	public String getSortAs() {
		if (StringUtils.isNotBlank(sortAs)) {
//			if (!sortAs.toLowerCase().matches(ParamsQuery.SORT_REGEX)) {
//				LOG.warn("#############排序字段格式不准确,忽略###########");
//				sortAs = null;
//			}
			if(entityClass == null){
				LOG.warn("#############entityClass未设置,无法映射数据库排序字段###########");
				sortAs = null;
			}
		}
		return sortAs;
	}
	

	public EntityQuery entityClassName(Class<?> entityClass) {
		this.entityClass = entityClass;
		return this;
	}
	

	public Class<?> getEntityClass() {
		return entityClass;
	}

	public String getWhere() {
		if(!params.isEmpty()){
			if(entityClass == null){
				LOG.warn("#############entityClass未设置,无法映射数据库排序字段###########");
				return where;
			}
			where = "1=1";
			String columnName;
			for (String propName : params.keySet()) {
				columnName = MybatisMapperResultConverter.property2ColumnName(entityClass, propName);
				if(StringUtils.isBlank(columnName))throw new RuntimeException(String.format("查询参数错误：未找到属性[%s]映射的数据库字段", propName));
				where = where + " and " + columnName + "='" + SqlChecker.paramsSafeFilter(params.get(propName).toString()) +"'";
			}
		}
		return where;
	}

	public Map<String, Object> getParams() {
		return params;
	}
	
	public boolean hasParams(){
		return !params.isEmpty();
	}
	
	public void clear(){
		params.clear();
	}
	
	/**
	 * 判断是否包含指定条件
	 * @param paramsNames
	 * @return
	 */
	public boolean existsParams(String...paramNames){
		if(paramNames == null || paramNames.length == 0)return true;
		for (String p : paramNames) {
			if(!params.containsKey(p))return false;
		}
		return true;
	}
	
	/**
	 * 判断是否包含其中任意条件
	 * @param paramNames
	 * @return
	 */
	public boolean existsAnyParams(String...paramNames){
		if(paramNames == null || paramNames.length == 0)return true;
		for (String p : paramNames) {
			if(params.containsKey(p))return true;
		}
		return false;
	}
	
	public static void main(String[] args) {}

}
